package org.bjf.aop;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bjf.modules.core.web.core.ThreadContext;
import org.bjf.utils.IpUtil;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 日志拦截器
 *
 * @author bjf
 */
@Slf4j
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class LogInterceptor extends HandlerInterceptorAdapter {

    private static final String TRACE_ID = "X-B3-TraceId";
    private static final ThreadLocal<Long> TIME_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // sleuth生成的traceId
        String traceId = request.getHeader(TRACE_ID);
        if (StringUtils.isNotBlank(traceId)) {
            MDC.put(TRACE_ID, traceId);
        }
        // 打印请求参数
        log.info("start uri:{},params:{},ip:{},user-agent:{}", request.getRequestURI(),
                JSONObject.toJSON(request.getParameterMap()),
                IpUtil.getIp(request), request.getHeader("User-Agent"));

        TIME_LOCAL.set(System.currentTimeMillis());
        return Boolean.TRUE;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 打印响应时间
        Long start = TIME_LOCAL.get();
        long consumeTime = System.currentTimeMillis() - start;
        String uri = request.getRequestURI();
        log.info("end uri:{},response time:{}", uri, consumeTime);

        if (consumeTime > 1000) {
            log.warn("uri:[{}]响应时间过长:[{} millis]", uri, consumeTime);
        }

        try {
            TIME_LOCAL.remove();
            ThreadContext.clear();
        } catch (Exception ignore) {
        }

        MDC.clear();
    }
}
